import {deepClone} from "@/libs/utils/ObjectClone";
import {fullPath, main, projectView} from "@/libs/lazyLoading";
import {
    getEventFromLocalStorage,
    getTagNavListFromSessionStorage,
    setEventToLocalStorage,
    setTagNavListInSessionStorage,
    getDynamicOpenTab,
    setDynamicOpenTab
} from "@/libs/menu/util";
import Vue from 'vue';
import {Base64} from 'js-base64'

let seed ={ };
const now = Date.now();
function getUuid (key='seq') {
    if(!seed[key]){
        seed[key] = 1;
    }
    return  key+ now + '-' + (seed[key]++);
}
const AfsEvent = new Vue({
});
const eventKey={}
export const forEach = (arr, fn) => {
    if (!arr.length || !fn) return
    let i = -1
    let len = arr.length
    while (++i < len) {
        let item = arr[i]
        fn(item, i, arr)
    }
}

export const daysOfYear = function (year,month,day){
    let num=0;
    month>1&&(num+=31);
    month>2&&(num+=(year%4===0&&year%100!==0||year%400===0?29:28));
    month>3&&(num+=31);
    month>4&&(num+=30);
    month>5&&(num+=31);
    month>6&&(num+=30);
    month>7&&(num+=31);
    month>8&&(num+=31);
    month>9&&(num+=30);
    month>10&&(num+=31);
    month>11&&(num+=30);
    return num+day;
};

/**
 * @param {Array} arr1
 * @param {Array} arr2
 * @description 得到两个数组的并集, 两个数组的元素为数值或字符串
 */
export const getUnion = (arr1, arr2) => {
    return Array.from(new Set([...arr1, ...arr2]))
}

/**
 * @param {String|Number} value 要验证的字符串或数值
 * @param {*} validList 用来验证的列表
 */
export function oneOf(value, validList) {
    for (let i = 0; i < validList.length; i++) {
        if (value === validList[i]) {
            return true
        }
    }
    return false
}

/**
 * @param {Number} num 数值
 * @returns {String} 处理后的字符串
 * @description 如果传入的数值小于10，即位数只有1位，则在前面补充0
 */
const getHandledValue = num => {
    return num < 10 ? '0' + num : num
}

/**
 * @returns {String} 当前浏览器名称
 */
export const getExplorer = () => {
    const ua = window.navigator.userAgent
    const isExplorer = (exp) => {
        return ua.indexOf(exp) > -1
    }
    if (isExplorer('MSIE')) return 'IE'
    else if (isExplorer('Firefox')) return 'Firefox'
    else if (isExplorer('Chrome')) return 'Chrome'
    else if (isExplorer('Opera')) return 'Opera'
    else if (isExplorer('Safari')) return 'Safari'
}

/**
 * @description 绑定事件 on(element, event, handler)
 */
export const on = (function () {
    if (document.addEventListener) {
        return function (element, event, handler) {
            if (element && event && handler) {
                element.addEventListener(event, handler, false)
            }
        }
    } else {
        return function (element, event, handler) {
            if (element && event && handler) {
                element.attachEvent('on' + event, handler)
            }
        }
    }
})()

/**
 * @description 解绑事件 off(element, event, handler)
 */
export const off = (function () {
    if (document.removeEventListener) {
        return function (element, event, handler) {
            if (element && event) {
                element.removeEventListener(event, handler, false)
            }
        }
    } else {
        return function (element, event, handler) {
            if (element && event) {
                element.detachEvent('on' + event, handler)
            }
        }
    }
})()

export const currencyFormat = (num, cent) => {
    /*
    * 参数说明：
    * num：要格式化的数字
    * cent：保留几位小数
    * */
    num = num.toString().replace(/\$|\,/g, '');

    // 检查传入数值为数值类型
    if (isNaN(num))
        num = "0";

    // 获取符号(正/负数)
    let sign = (num == (num = Math.abs(num)));

    num = Math.floor(num * Math.pow(10, cent) + 0.50000000001); // 把指定的小数位先转换成整数.多余的小数位四舍五入
    let cents = num % Math.pow(10, cent);       // 求出小数位数值
    num = Math.floor(num / Math.pow(10, cent)).toString();  // 求出整数位数值
    cents = cents.toString();        // 把小数位转换成字符串,以便求小数位长度

    // 补足小数位到指定的位数
    while (cents.length < cent)
        cents = "0" + cents;

    // 对整数部分进行千分位格式化.
    for (var i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++)
        num = num.substring(0, num.length - (4 * i + 3)) + ',' + num.substring(num.length - (4 * i + 3));

    if (cent > 0)
        return (((sign) ? '' : '-') + num + '.' + cents);
    else
        return (((sign) ? '' : '-') + num);
}

export const numberFormat = (num, cent) => {
    /*
    * 参数说明：
    * num：要格式化的数字
    * cent：保留几位小数
    * */
    num = num.toString().replace(/\$|\,/g, '');

    // 检查传入数值为数值类型
    if (isNaN(num))
        num = "0";
    // 获取符号(正/负数)
    let sign = (num == (num = Math.abs(num)));

    num = Math.floor(num * Math.pow(10, cent) + 0.00000000001); //
    let cents = num % Math.pow(10, cent);       // 求出小数位数值
    num = Math.floor(num / Math.pow(10, cent)).toString();  // 求出整数位数值
    cents = cents.toString();        // 把小数位转换成字符串,以便求小数位长度

    // 补足小数位到指定的位数
    while (cents.length < cent)
        cents = "0" + cents;

    for (let i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++)
        num = num.substring(0, num.length - (4 * i + 3))  + num.substring(num.length - (4 * i + 3));

    if (cent > 0)
        return (((sign) ? '' : '-') + num + '.' + cents);
    else
        return (((sign) ? '' : '-') + num);
}
/**
 * 百分比转换为小数
 * @param num
 * @param cent
 * @returns {string}
 */
export const percentageParse = (num, cent) => {
    /*
    * 参数说明：
    * num：要格式化的数字
    * cent：保留几位小数
    * */
    num = num/100;
    num = num.toString().replace(/\$|\,/g, '');

    // 检查传入数值为数值类型
    if (isNaN(num))
        num = "0";
    // 获取符号(正/负数)
    let sign = (num == (num = Math.abs(num)));

    num = Math.floor(num * Math.pow(10, cent) + 0.00000000001); //
    let cents = num % Math.pow(10, cent);       // 求出小数位数值
    num = Math.floor(num / Math.pow(10, cent)).toString();  // 求出整数位数值
    cents = cents.toString();        // 把小数位转换成字符串,以便求小数位长度

    // 补足小数位到指定的位数
    while (cents.length < cent)
        cents = "0" + cents;

    for (let i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++)
        num = num.substring(0, num.length - (4 * i + 3))  + num.substring(num.length - (4 * i + 3));

    if (cent > 0)
        return (((sign) ? '' : '-') + num + '.' + cents);
    else
        return (((sign) ? '' : '-') + num);
}

export const convertCurrencyToChinese = currency => {
    // 汉字的数字
    const cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
    // 基本单位
    const cnIntRadice = ['', '拾', '佰', '仟']
    // 对应整数部分扩展单位
    const cnIntUnits = ['', '万', '亿', '兆']
    // 对应小数部分单位
    const cnDecUnits = ['角', '分', '毫', '厘']
    // 整数金额时后面跟的字符
    const cnInteger = '整'
    // 整型完以后的单位
    const cnIntLast = '元'
    // 最大处理的数字
    const maxNum = 999999999999.99
    // 金额整数部分
    let integerNum
    // 金额小数部分
    let decimalNum
    // 输出的中文金额字符串
    let chineseStr = ''
    // 分离金额后用的数组，预定义
    let parts
    if (!currency||currency === '') { return '' }
    let money = deepClone(currency);
    if (money >= maxNum) {
        // 超出最大处理数字
        return '金额太大'
    }
    if (money === 0) {
        chineseStr = cnNums[0] + cnIntLast + cnInteger
        return chineseStr
    }
    // 转换为字符串
    money = money.toString()
    if (money.indexOf('.') === -1) {
        integerNum = money
        decimalNum = ''
    } else {
        parts = money.split('.')
        integerNum = parts[0]
        decimalNum = parts[1].substr(0, 4)
    }
    chineseStr+=(money.startsWith('-')?'负':'')
    // 获取整型部分转换
    if (parseInt(integerNum, 10) > 0) {
        let zeroCount = 0
        let IntLen = integerNum.length
        for (let i = 0; i < IntLen; i++) {
            let n = integerNum.substr(i, 1)
            let p = IntLen - i - 1
            let q = p / 4
            let m = p % 4
            if (n === '0') {
                zeroCount++
            } else {
                if (zeroCount > 0) {
                    chineseStr += cnNums[0]
                }
                // 归零
                zeroCount = 0
                chineseStr += cnNums[parseInt(n)] + cnIntRadice[m]
            }
            if (m === 0 && zeroCount < 4) {
                chineseStr += cnIntUnits[q]
            }
        }
        chineseStr += cnIntLast
    }
    // 小数部分
    if (decimalNum !== '') {
        let decLen = decimalNum.length
        for (let i = 0; i < decLen; i++) {
            let n = decimalNum.substr(i, 1)
            if (n !== '0') {
                chineseStr += cnNums[Number(n)] + cnDecUnits[i]
            }
        }
    }
    if (chineseStr === '') {
        chineseStr += cnNums[0] + cnIntLast + cnInteger
    } else if (decimalNum === '') {
        chineseStr += cnInteger
    }
    return chineseStr
}

export const genDynamicRoute=(uPath, componentPath, title, icon, params, index, permission=[], isFull = false,pathHash,menusParams,opener='')=>{
    let randomPath = getUuid('ui-tab-');
    let component = isFull?(fullPath(componentPath)):projectView(componentPath);
    let dRoute = {
        component: main(),
        title: title,
        name: randomPath,
        icon: icon,
        path: '/'+index,
        meta: {
            title: title,
            keepAlive: true,
            icon: icon,
            dynamicTab:true
        },
        children: [
            {
                component: component,
                title: title,
                name: uPath,
                icon: icon,
                path: '/'+index+'/'+uPath,
                meta: {
                    permTypes: permission,
                    title: title,
                    name: uPath,
                    eventHashKey:pathHash,
                    keepAlive: true,
                    icon: icon,
                    dynamicTab:true,
                    params:params,
                    dIndex:index,
                    componentPath:componentPath,
                    isFull:isFull,
                    menusParams:menusParams,
                    openPath:opener
                },
            }
        ]
    };
    return dRoute;
}

/**
 *
 * @param vm
 * @param componentPath 组件路径
 * @param title 标题
 * @param icon 图标
 * @param params 参数
 * @param index 唯一索引，
 * @param permission 权限标记数据
 * @param isFull 组件是否为全路径 全路径指 相对于src ，非全路相对于当前开发项目来说
 */
export const newTab = (vm,componentPath,title,icon,params,index,permission=[],isFull = false)=>{
    if(!index||index==''){
        throw new Error('标签页index不能为空');
    }
    let randomPath = getUuid('ui-tab-');
    let menusParams =  vm.$route.meta.menusParams;
    let dRoute = genDynamicRoute(randomPath,componentPath,title,icon,params,index,permission,isFull,getHash(vm),menusParams,vm.$route.name)
    vm.$store.dispatch('addNewTab', dRoute)
        .then(()=>{
        vm.$store.commit('updateDynamicTab',{tabIndex:index,uuid:randomPath})
    });
}


export const closeTab = (vm)=>{
    if(vm.$route.query._link){
        let userAgent = navigator.userAgent;
        if (userAgent.indexOf("Firefox") != -1 || userAgent.indexOf("Chrome") !=-1) {
            window.location.href="about:blank";
            window.close();
        } else {
            window.opener = null;
            window.open("", "_self");
            window.close();
        }
        return;
    }
    let {name, query, params, meta} = vm.$route
    getTagNavListFromSessionStorage().forEach(tag=>{
        if(tag.name==name){
            name = tag.name;
            params = tag.meta.params;
            query = tag.query;
            meta = tag.meta;
        }
    })
    vm.$store.commit('closeTag',{name, query, params, meta})
}

export const  getUri= (type)=>{
    return _AFS_PROJECT_CONFIG.componentRequestUri[type]
}

export const  webSocketUri= ()=>{
    return _AFS_PROJECT_CONFIG.webSocketUri
}

export const getPageParams = (vm)=> {
    if (vm.$route.query._link) {
        const jsonData = JSON.parse(Base64.decode(vm.$route.query._link,true));
        return  jsonData.pageData.params;
    } else {
        let {name} = vm.$route,params=null;
        getTagNavListFromSessionStorage().forEach(tag => {
            if (tag.name == name) {
                params = tag.meta.params;
            }
        })
        return params;
    }
}

export const updatePageParams = (vm,params={})=> {
    let {name} = vm.$route;
    let tagNavList = getTagNavListFromSessionStorage();
    let dynamicList = getDynamicOpenTab();
    tagNavList.forEach(tag => {
        if (tag.name === name) {
            if(tag.meta.params) {
                tag.meta.params = Object.assign(tag.meta.params, params)
            }else{
                tag.meta.params = params
            }
            if(tag.params){
                tag.params =  Object.assign(tag.params, params);
            }else{
                tag.params = params;
            }
        }
    })
    dynamicList.forEach(tag => {
        if (tag.name === name) {
            if(tag.meta.params) {
                tag.meta.params = Object.assign(tag.meta.params, params)
            }
        }
    })
    setTagNavListInSessionStorage(tagNavList);
    setDynamicOpenTab(dynamicList)
}

export const getMenuParams = (vm)=> {
    if (vm.$route.meta.menusParams) {
       return vm.$route.meta.menusParams;
    } else {
        return {};
    }
}


function getTabPageEventHash (vm){
    let {name} = vm.$route,eventHashKey=undefined;
    getTagNavListFromSessionStorage().forEach(tag => {
        if (tag.name === name) {
            eventHashKey = tag.meta.eventHashKey;
        }
    })
    return eventHashKey;
}
function getBrowserTabPageEventHash (vm){
    if (vm.$route.query._link) {
        const jsonData = JSON.parse(Base64.decode(vm.$route.query._link,true));
        return  jsonData.pageData.eventHashKey;
    }
    return undefined;
}


function getHash(vm) {
    let {name} = vm.$route;
    return  md5(name);
}

export const bindEvent=(vm,eventName,callback)=>{
    let hashKey = getHash(vm);
    eventKey[hashKey] = true;
    let eventFire = false;
    setEventToLocalStorage(hashKey, eventName,[])
    AfsEvent.$on(hashKey+'-'+eventName,(params)=>{
        if(eventFire){
            console.log(hashKey+'-'+eventName+'正在触发中......')
            return;
        }
        eventFire = true;
        try {
            callback(params.params);
            let events = getEventFromLocalStorage(hashKey, eventName).filter(event => {
                return event.eventId != params.eventId;
            })
            setEventToLocalStorage(hashKey, eventName, events);
        }finally {
            eventFire = false;
        }
    });
    function innerFireEvent(){
        if(eventFire){
            console.log(hashKey+'-'+eventName+'正在触发中......')
            if(eventKey[hashKey]) {
                setTimeout(fireEvent, 10)
            }
            return;
        }
        eventFire = true;
        let events = getEventFromLocalStorage(hashKey,eventName);
        let event = events.shift();
        if(event) {
            try {
                callback(event.params)
                events = getEventFromLocalStorage(hashKey, eventName).filter(ev => {
                    return event.eventId != ev.eventId;
                })
                setEventToLocalStorage(hashKey, eventName, events);
               if(events.length==0&&!eventKey[hashKey]){
                    delete eventKey[hashKey];
                    return;
                }
            }finally {
                eventFire = false;
            }
        }else{
            eventFire = false;
        }
        if(eventKey[hashKey]){
            setTimeout(innerFireEvent, 10)
        }
    }
    setTimeout(innerFireEvent,10);
}

export const fireEvent=(vm,eventName,params)=>{
    //自身事件触发
    AfsEvent.$emit(getHash(vm)+'-'+eventName,params);
    //打开tab页事件触发
    let tabEventHashKey = getTabPageEventHash(vm);
    const eventUUid = getUuid('event-');
    const event={
        params:params,
        eventId:eventUUid
    }
    if(tabEventHashKey) {
        AfsEvent.$emit(tabEventHashKey + '-' + eventName, event);
    }
    let browserTabEventHashKey = getBrowserTabPageEventHash(vm);
    if(browserTabEventHashKey) {
        let events = getEventFromLocalStorage(browserTabEventHashKey, eventName);
        events.push(event);
        setEventToLocalStorage(browserTabEventHashKey,eventName,events);
    }
}

export const destoryEvent=(vm,eventName)=>{
    AfsEvent.$off(getHash(vm)+'-'+eventName);
    eventKey[getHash(vm)] = false;
}
export const checkHoliday=(date,cacheHolidayInfo)=>{
    const _year = date.getFullYear()+'',
        _dayOfYear = daysOfYear(date.getFullYear(),date.getMonth()+1,date.getDate());
    if(!cacheHolidayInfo[_year]){
        return true
    }
    return cacheHolidayInfo[_year].charAt(_dayOfYear-1)==='1';

}

